﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Settings;
using Constants = Red.Scripts.Defines.Constants;

namespace Red.Scripts.Options.SccSearchOrder
{
    public class SearchOrderConverter : TypeConverter
    {
        #region TypeConverter

        public override bool CanConvertFrom( ITypeDescriptorContext context, Type sourceType )
        {
            if ( sourceType == typeof( string ) )
                return true;

            return base.CanConvertFrom( context, sourceType );
        }

        public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType )
        {
            if ( destinationType == typeof( string ) )
                return true;

            return base.CanConvertTo( context, destinationType );
        }

        public override object ConvertFrom( ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value )
        {
            if ( value is string )
            {
                string valueStr = (string)value;
                string[] values = valueStr.Split( ';' );

                IEnumerable<Defines.SccSearchOrder> convertedValues;
                try
                {
                    convertedValues = from str in values select (Defines.SccSearchOrder)Enum.Parse( typeof( Defines.SccSearchOrder ), str );
                }
                catch ( ArgumentException )
                {
                    return null;
                }

                return convertedValues;
            }

            return base.ConvertFrom( context, culture, value );
        }

        public override object ConvertTo( ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType )
        {
            if ( value is IEnumerable<Defines.SccSearchOrder> && destinationType == typeof( string ) )
            {
                IEnumerable<Defines.SccSearchOrder> values = (IEnumerable<Defines.SccSearchOrder>)value;

                return string.Join( ";", from item in values select item.ToString() );
            }

            return base.ConvertTo( context, culture, value, destinationType );
        }

        #endregion TypeConverter
    }

    [Guid( Defines.Guids.Options.SccSearchOrder.Raw )]
    public class Page : UIElementDialogPage
    {
        #region Private Data

        private Defines.Settings _settings;
        private Ctrl _ctrl = new Ctrl();

        #endregion Private Data

        #region C-Tor

        public Page()
        {
            var componentModel = (IComponentModel)ServiceProvider.GlobalProvider.GetService( typeof( SComponentModel ) );
            _settings = componentModel.GetService<Defines.Settings>();
        }

        #endregion C-Tor

        #region Private methods

        private bool Restore()
        {
            _ctrl.ItemsSource.Clear();

            IEnumerable<Defines.SccSearchOrder> searchOrder = (IEnumerable<Defines.SccSearchOrder>)_settings[ Defines.Setting.SccSearchOrder ];

            if ( searchOrder == null )
                return false;

            if ( searchOrder.Count() != Enum.GetValues( typeof( Defines.SccSearchOrder ) ).Length )
                return false;

            foreach ( Defines.SccSearchOrder item in searchOrder )
            {
                _ctrl.ItemsSource.Add( item );
            }

            _ctrl.CustomSearchPath = (string)_settings[ Defines.Setting.SccCustomSearchPath ];

            return true;
        }

        private void Defaults()
        {
            _ctrl.ItemsSource.Clear();

            foreach ( Defines.SccSearchOrder value in Enum.GetValues( typeof( Defines.SccSearchOrder ) ) )
            {
                _ctrl.ItemsSource.Add( value );
            }
        }

        #endregion Private methods

        #region UIElementDialogPage

        protected override UIElement Child => _ctrl;

        protected override void OnApply( PageApplyEventArgs e )
        {
            if ( e.ApplyBehavior == ApplyKind.Apply )
            {
                var values = from item in _ctrl.ItemsSource select item.Value;

                _settings[ Defines.Setting.SccSearchOrder ] = values;
                _settings[ Defines.Setting.SccCustomSearchPath ] = _ctrl.CustomSearchPath;
            }

            base.OnApply( e );
        }

        public override void SaveSettingsToStorage()
        {
            base.SaveSettingsToStorage();

            var settingsManager = new ShellSettingsManager( ServiceProvider.GlobalProvider );
            var userSettingsStore = settingsManager.GetWritableSettingsStore( SettingsScope.UserSettings );

            if ( !userSettingsStore.CollectionExists( Constants.Options.SccSearchOrder.Collection ) )
                userSettingsStore.CreateCollection( Constants.Options.SccSearchOrder.Collection );

            var converter = new SearchOrderConverter();

            var searchOrder = (IEnumerable<Defines.SccSearchOrder>)_settings[ Defines.Setting.SccSearchOrder ];
            if ( searchOrder != null )
                userSettingsStore.SetString( Constants.Options.SccSearchOrder.Collection, Constants.Options.SccSearchOrder.Name, (string)converter.ConvertTo( searchOrder, typeof( string ) ) );

            var customSearchPath = (string)_settings[ Defines.Setting.SccCustomSearchPath ];
            if ( customSearchPath != null )
                userSettingsStore.SetString( Constants.Options.SccSearchOrder.Collection, Constants.Options.SccSearchOrder.CustomPath, customSearchPath );
        }

        public override void LoadSettingsFromStorage()
        {
            base.LoadSettingsFromStorage();

            var settingsManager = new ShellSettingsManager( ServiceProvider.GlobalProvider );
            var userSettingsStore = settingsManager.GetReadOnlySettingsStore( SettingsScope.UserSettings );

            if ( userSettingsStore.PropertyExists( Constants.Options.SccSearchOrder.Collection, Constants.Options.SccSearchOrder.Name ) )
            {
                var converter = new SearchOrderConverter();
                _settings[ Defines.Setting.SccSearchOrder ] = (IEnumerable<Defines.SccSearchOrder>)converter.ConvertFrom( userSettingsStore.GetString( Constants.Options.SccSearchOrder.Collection, Constants.Options.SccSearchOrder.Name ) );
            }

            if ( userSettingsStore.PropertyExists( Constants.Options.SccSearchOrder.Collection, Constants.Options.SccSearchOrder.CustomPath ) )
            {
                _settings[ Defines.Setting.SccCustomSearchPath ] = userSettingsStore.GetString( Constants.Options.SccSearchOrder.Collection, Constants.Options.SccSearchOrder.CustomPath );
            }

            if ( !Restore() )
                Defaults();
        }
        #endregion UIElementDialogPage
    }
}
